#!/usr/bin/python
# -*- coding: utf-8 -*-

import os
import sys
import traceback
import datetime

from common.pathmgr import PathConfig
from common.filelocker import FileLocker


class ExceptionManager(object):
    MaxLogSize = 1024 * 1024 * 20
    ProjectPath = PathConfig.PROJECT_FOLDER

    def __init__(self, logDir=None):
        self.__logDir = logDir
        if self.__logDir == None:
            self.__logDir = PathConfig.EXCEPTION

    def on_except(self, msg=None, inMonitor=False):
        logFile = None
        s = None
        locker = None
        try:
            etype, value, tb = sys.exc_info()
            f = tb.tb_frame
            co = f.f_code
            code_path = co.co_filename
            if code_path.startswith(self.ProjectPath):
                code_path = code_path[len(self.ProjectPath):]
                if code_path[0] in ("\\", "/"):
                    code_path = code_path[1:]
                filename = code_path.replace("\\", ".").replace("/", ".")
            else:
                filename = os.path.basename(code_path)

            if inMonitor:
                new_t = tb.tb_next
                if new_t:
                    new_co = new_t.tb_frame.f_code
                    filename = os.path.basename(new_co.co_filename)
                    s = ''.join(traceback.format_exception(etype, value, new_t, 10))
            else:
                s = traceback.format_exc(10)
            logPath = self.__getLogPath(filename)
            locker = FileLocker(logPath)
            locker.lock()
            if os.path.isfile(logPath) and os.path.getsize(logPath) >= ExceptionManager.MaxLogSize:
                self.__backupLog(logPath)
            logFile = open(logPath, "a")
            logFile.write("========================%s%s:%s" % (os.linesep, datetime.datetime.now(), os.linesep))
            logFile.write(s)
            if msg:
                logFile.write(msg)
                logFile.write(os.linesep)
            logFile.write(os.linesep + "========================" + os.linesep)
        except:
            self.__printSelfException()
        try:
            if logFile:
                logFile.close()
            if locker:
                locker.unlock()
        except:
            self.__printSelfException()
        try:
            print(s)
        except:
            pass
        return s

    def __backupLog(self, logPath):
        p1, p2 = os.path.splitext(logPath)
        bakPath1 = p1 + "_bak" + p2
        bakPath2 = p1 + "_bak_bak" + p2
        if os.path.exists(bakPath1):
            if os.path.exists(bakPath2):
                os.remove(bakPath2)
            os.rename(bakPath1, bakPath2)
        os.rename(logPath, bakPath1)

    def __printSelfException(self):
        try:
            print("ExceptionManager self errors")
            print(traceback.format_exc(10))
        except:
            pass

    def __getLogPath(self, fileName):
        if not fileName:
            fileName = "except.log"
        else:
            fileName = os.path.splitext(fileName)[0] + ".log"
        if not os.path.exists(self.__logDir):
            try:
                os.makedirs(self.__logDir)
            except OSError as e:
                if e.args[0] == 17:
                    pass
                else:
                    raise
        return os.path.join(self.__logDir, fileName)


__exceptObjInExceptionMgr = None


def on_except(msg=None, inMonitor=False):
    global __exceptObjInExceptionMgr
    if not __exceptObjInExceptionMgr:
        __exceptObjInExceptionMgr = ExceptionManager()
    return __exceptObjInExceptionMgr.on_except(msg, inMonitor)


def except_moniter(function):
    def moniter(*args, **argkv):
        try:
            return function(*args, **argkv)
        except:
            on_except(None, True)
            raise

    return moniter


@except_moniter
def testMoniter():
    1 / 0


if __name__ == "__main__":
    testMoniter()
    try:
        os.path.basename(None)
    except:
        on_except()
